/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file demo_character.hpp
 * @author TooOld2Rock'nRoll
 * @date 2024/03/06
 * @brief A example character for the ArcadeFighter Library.
 *
 * @todo Use the loading thread for resources....
 * @todo Falling is now implemented in two places (jump and long jump states update), need a physics class!
 * @todo Import character statistics from a file.
 * @todo Import character animations from a file.
 */
#ifndef _DEMO_CHARACTER_HPP_
#define _DEMO_CHARACTER_HPP_

/*---- Includes ----*/
#include "character.hpp"


/*---- Enums ----*/
extern "C" {
typedef enum _extended_commands_
{
    LIGHT_PUNCH = character_commands_t::_command_max, //<-- enumeration will start where character_commands ended
    HARD_PUNCH,
    SHORT_JUMP,
    LONG_JUMP,
    CROUCH_WALK,
    RUN,
    _extend_command_max
} extended_character_commands_e;

typedef enum _extended_char_state_
{
    ROLLING = character_state_t::_state_max, //<-- enumeration will start where character_state ended
    DASHING, ///< Character is in the middle of a dash.
    CROUCH_WALKING,
    RUNNING, ///<Double left/right click-hold
    LONG_JUMPIMP, ///<Jump from running.
    _extend_state_max
} extended_character_state_e;
}//end extern "C"


/*---- Class Declaration ----*/
/**
 * @brief A example of how a character could be implemented extending the Character class.
 * @extends Character
 */
class DemoCharacter : public Character
{
    public:
        enum animation_list_e
        {
            LOADING = 0,
            OPENING_ANIME, //no animation yet!
            WIN, //no animation yet!
            LOSE,
            IDLE,
            WALKING,
            RUNNING,
            DASHING, //no animation yet!
            ROLLING,
            CROUCH_IDLE,
            CROUCH_WALKING,
            JUMP,
            AIR_SPIN,
            LAND,
            BLOCK,
            JAB,
            CROSS,
            _anime_max ///< Just to keep count of enum size.
        };//end animation_list

        enum audio_effect_list_e
        {
            SOUND_LIGHT_PUNCH = 0,
            SOUND_HARD_PUNCH,
            SOUND_JUMP,
            SOUND_LAND,
            _audio_effect_max ///< Just to keep count of enum size.
        };//end audio_effect_list_e


    private:
        Audio::Effect *punch = nullptr;

        void _populateDefaultCommandList ();
        void _populateDefaultStatesList ();
        void _populateDefaultChainActions ();


    protected:


    public:
        DemoCharacter (DomainID_t domain_id, Shader *sh);

        virtual void load () override final;
};//END DemoCharacter

/*---- Custom Commands ----*/
/** @brief Command that makes the Character move in walking speed. */
class WalkCommand : public Command<DemoCharacter>
{ virtual void execute (DemoCharacter &puppet, double delta_t) override; };

/** @brief Command that makes the Character move in running speed. */
class RunCommand : public Command<DemoCharacter>
{ virtual void execute (DemoCharacter &puppet, double delta_t) override; };

/** @brief Command that makes the Character jump. */
class JumpCommand : public Command<DemoCharacter>
{ virtual void execute (DemoCharacter &puppet, double delta_t) override; };

/** @brief Command that makes the Character do a shot forward/backward jump. */
class ShortJumpCommand : public Command<DemoCharacter>
{ virtual void execute (DemoCharacter &puppet, double delta_t) override; };

/** @brief Command that makes the Character do a long forward/backward jump. */
class LongJumpCommand : public Command<DemoCharacter>
{ virtual void execute (DemoCharacter &puppet, double delta_t) override; };

/** @brief Command that makes the Character attack with a light punch. */
class LightPunchCommand : public Command<DemoCharacter>
{ void execute (DemoCharacter &puppet, double delta_t) override final; };

/** @brief Command that makes the Character attack with a hard punch. */
class HardPunchCommand : public Command<DemoCharacter>
{ void execute (DemoCharacter &puppet, double delta_t) override final; };

/** @brief Command that makes the Character move in crouched speed. */
class CrouchWalkCommand : public Command<DemoCharacter>
{ void execute (DemoCharacter &puppet, double delta_t) override final; };

/*---- Custom States ----*/
/** @brief A state to uso on loading screens. */
class LoadingState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::LOADING); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final
        { return true; }

        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final
        { /* ignore all */ }

        void update (DemoCharacter &puppet, double delta_t) override final
        { puppet.getActiveSprite().update (delta_t); }
};//END IdleState

/** @brief A basic Idle state. */
class IdleState : public AutomatedState<DemoCharacter>
{
    public:
        IdleState ();

        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::IDLE); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END IdleState

/** @brief A basic walking state. */
class WalkingState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final;
        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END WalkingState

/** @brief A extended running state. */
class RunningState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final;
        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END RunningState

/** @brief A basic crouch state. */
class CrouchState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::CROUCH_IDLE); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END CrouchState

/** @brief A extended crouch walking state. */
class CrouchWalkingState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::CROUCH_WALKING); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END CrouchWalkingState

/** @brief A basic jumping state. */
class JumpingState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::JUMP); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END JumpingState

/** @brief A extended jumping state. */
class LongJumpState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::AIR_SPIN); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END LongJumpState

/** @brief A basic attack state. */
class AttackState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final { /*changes depending on the attack command!*/ }
        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END AttackState

/** @brief A basic blocking state. */
class BlockState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final
        { puppet.setActiveSprite (DemoCharacter::animation_list_e::BLOCK); }

        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END BlockState

/** @brief A extended rolling state. */
class RollingState : public State<DemoCharacter>
{
    public:
        void enter (DemoCharacter &puppet) override final;
        bool checkStateChange (DemoCharacter &puppet, unsigned new_state) const override final;
        void handleInput (DemoCharacter &puppet, controller_button_map_t input, key_state input_st, double delta_t) override final;
        void update (DemoCharacter &puppet, double delta_t) override final;
};//END LongJumpState

#endif //_DEMO_CHARACTER_HPP_

